#include "cppThreadPool.h"

// 工作线程部分
workThread::workThread(threadPool* p, int Id):workId(Id), pool(p) {
    spdlog::info("创建线程, workId 是: " + std::to_string(this->workId));
}

workThread::~workThread() {
    if (this->workId != -1) {
        spdlog::info("工作线程析构, workId 是: " + std::to_string(this->workId));
    }
}

workThread::workThread(workThread&& work) {
    // 避免自复制
    if (this != &work) {
        this->pool = work.pool;
        this->workId = work.workId;
        work.pool = nullptr;
        work.workId = -1;
    }
}

workThread& workThread::operator=(workThread&& work) {
    // 需要避免自赋值
    if (this == &work) {
        return *this;
    }
    
    *this = std::forward<workThread>(work);
    return *this;
}

void workThread::operator()() {
    // 这里重载()是必须的,std::thread需要一个可调用对象
    // std::thread的第一个参数不止是函数，还可以是一个可调用对象，即支持operator()(Args...)操作
    
    std::function<void()> func; // 基础函数类

    bool isGetTask(false);
    
    while(this->pool->getPoolIsWork()) {
        // 检查线程是否工作， 如果关闭线程池，调度过程终止
        isGetTask = this->pool->getTaskFromQueue(func);

        if (isGetTask) {
            func();
        }
    }
}

// 线程池部分
bool threadPool::getPoolIsWork() {
    return this->poolIsWork;
}

bool threadPool::getTaskFromQueue(std::function<void()>& func) {
    
    std::unique_lock<std::mutex> lock(this->poolMutex);

    // 如果任务队列为空 阻塞线程  wait表示线程阻塞 等待被唤醒
    if (this->taskQueue.empty()) {
        // std::condition_variable conditionLock 注意该成员变量
        // 条件变量和锁机制搭配使用 执行到wait()函数的时候 自动的释放锁 线程阻塞
        spdlog::info("任务队列为空,条件变量阻塞线程！！");
        this->conditionLock.wait(lock);
    }


    return this->taskQueue.getTask(func);
}

// 定义线程池其他函数

threadPool::threadPool(unsigned int threadNum):poolIsWork(true), threadVec(std::vector<std::thread>(threadNum)) {
    for (unsigned int threadId(0); threadId < threadNum; threadId++) {
        threadVec.at(threadId) = std::thread(workThread(this, threadId));
    }
    spdlog::info("成功创建线程池！");
}

void threadPool::shutDown() {
    this->poolIsWork = false;
    this->conditionLock.notify_all(); // 唤醒所有工作线程, 执行关闭操作
    for (size_t idx(0); idx < this->threadVec.size(); idx++) {
        if (this->threadVec.at(idx).joinable()) {
            threadVec.at(idx).join(); // 如果线程没有执行结束，join等待
        }
    }

}


threadPool::~threadPool() {
    if (this->poolIsWork) {
        this->shutDown();
    }
    spdlog::info("成功析构线程池！");
}
